<?php

namespace App\Console\Commands;

use App\Models\Attendance\Attendance;
use App\Models\Attendance\AttendanceCollect;
use App\Models\Personnel\PersonnelCleaner;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;


class syncAttendanceCollect extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sync:attendance_collect';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '同步考勤汇总数据';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * 注意事项
     * 首次手动执行php artisan命令时请清空表akbus_attendance_collect数据
     * 接着请按需注释掉(打开)部分代码然后将此文件添加到定时任务中
     * 定时任务执行时间必须放在同步完考勤数据之后
     *
     * @return void
     */
    public function handle(): void
    {
        // // 初次执行需要将数据库所有数据导入
        // $startDate = DB::table('akbus_attendance')->min('actual_sign_time');
        // $startDate = date('Y-m-d', strtotime($startDate));
        // $endDate = DB::table('akbus_attendance')->max('actual_sign_time');
        // $endDate = date('Y-m-d', strtotime($endDate));
        // $date_array = $this->printDates($startDate, $endDate);
        // // 获取清洁工人员名单
        // $cleaner = PersonnelCleaner::query()->get()->pluck('name')->toArray();
        // foreach ($date_array as  $last_day) {
        //     $this->insertData($last_day, $cleaner);
        // }
        //此后每天同步考勤时运行以下代码即可
        $yesterday = date('Y-m-d', strtotime('-1 day'));
        $cleaner = PersonnelCleaner::query()->get()->pluck('name')->toArray();
        $this->insertData($yesterday, $cleaner);
    }

    public function insertData($last_day, $cleaner)
    {
        //记录日志
        $this->info('- ' . $last_day);
        Storage::append('syncAttendanceCollect.log', 'Date: ' . $last_day);
        Storage::append('syncAttendanceCollect.log', 'DateTime: ' . date('Y-m-d H:i:s'));
        //获取数据
        $data = Attendance::query()
            ->whereNotIn('driver', $cleaner)
            ->whereDate('actual_sign_time', $last_day)
            ->orderBy('license_plate_num', 'asc')
            ->get()
            ->toArray();
        if ($data) {
            $data = $this->transData($data, $last_day);
            //将数据写入考勤汇总表
            $attendanceCollect = new AttendanceCollect();
            $result = $attendanceCollect->insert($data);
            if ($result) {
                $this->info('- Table akbus_attendance_collect Insert Success' . PHP_EOL);
                Storage::append('syncAttendanceCollect.log', 'Result: Table akbus_attendance_collect Insert Success');
                //根据写入数据继续为akbus_bus_attendance_collect表,akbus_driver_attendance_collect表写入数据
                
                //汇总车辆考勤                
                $busReport = $this->getReportData($last_day, 'busNumber');
                $busAttendance = $this->getAttendanceData($last_day, 'busNumber');
                $bus_data = $this->mergeData($busAttendance, $busReport, 'busNumber');
                //汇总驾驶员考勤                
                $driverReport = $this->getReportData($last_day, 'driver');
                $driverAttendance = $this->getAttendanceData($last_day, 'driver');
                $driver_data = $this->mergeData($driverAttendance, $driverReport, 'driver');
                DB::beginTransaction(); //开启事务
                try {
                    DB::table('akbus_bus_attendance_collect')->insert($bus_data);
                    DB::table('akbus_driver_attendance_collect')->insert($driver_data);
                    DB::commit();  //提交
                    $this->info('-Table akbus_bus_attendance_collect And akbus_driver_attendance_collect Insert Success');
                    Storage::append('syncAttendanceCollect.log', 'Result: -Table akbus_bus_attendance_collect And akbus_driver_attendance_collect Insert Success');
                } catch (\Throwable $th) {
                    DB::rollBack();
                    $this->info('- Insert Failure' . $th->getMessage());
                    Storage::append('syncAttendanceCollect.log', 'Result: -Table akbus_bus_attendance_collect And akbus_driver_attendance_collect Insert Failure' . $th->getMessage());
                }
            } else {
                $this->info('- Table akbus_attendance_collect Insert Failure' . PHP_EOL);
                Storage::append('syncAttendanceCollect.log', 'Result: Table akbus_attendance_collect Insert Failure');
            }
        } else {
            $this->info('- Msg: The fetch data is null' . PHP_EOL);
            $time = date('Y-m-d H:i:s');
            Storage::append('syncAttendanceCollect.log', 'Result: Get Failure,Msg: The fetch data is null,Read access time:' . $time);
        }
    }

    //数据转化
    public function transData($data, $last_day)
    {
        $festival = DB::table('akbus_holiday')->pluck('holiday_date')->toArray();
        $data = collect($data)->groupBy('license_plate_num')->toArray();
        $postData = [];
        foreach ($data as $license_plate_num => $bus_date) {

            $driver_date = collect($bus_date)->groupBy('driver')->toArray();
            foreach ($driver_date as $name => $driver) {
                $sign_number = count($driver); //打卡次数
                $minDate = searchMin($driver, 'actual_sign_time');
                $start_sign_time = UTC2Normal($minDate, 'H:i:s'); //最早打卡时间
                $maxDate = searchMax($driver, 'actual_sign_time');
                $end_sign_time = UTC2Normal($maxDate, 'H:i:s'); //最晚打卡时间
                $workHour = number_format((strtotime($maxDate) - strtotime($minDate)) % 86400 / 3600, 1);
                $maxHours = UTC2Normal($maxDate, 'H');
                $normalHour = $maxHours <= 12 ? 4.5 : 5.5;
                if ($workHour >= $normalHour && $workHour < 10) {
                    $normalTime = 0.5;
                } elseif ($workHour >= 10) {
                    $normalTime = 1;
                } else {
                    $normalTime = 0;
                }
                $line = implode(',', array_unique(array_column($driver, 'line'))); //线路
                $normal_time = $normalTime; //正常班时间
                $over_time = in_array($last_day, $festival, true) ? 1 : 0; // 加班时间
                // $night_over_time = $end_sign_time >= '21:00:00' ? 1 : 0; //晚上加班时间
                $night_over_time = 0; //晚上加班时间
                $attendance = [
                    'line'              => $line,
                    'license_plate_num' => $license_plate_num,
                    'driver'            => $name,
                    'start_sign_time'   => $start_sign_time,
                    'end_sign_time'     => $end_sign_time,
                    'sign_number'       => $sign_number,
                    'work_hours'        => $workHour,
                    'sign_date'         => $last_day,
                    'normal_time'       => $normal_time,
                    'over_time'         => $over_time,
                    'night_over_time'   => $night_over_time,
                    'created_at'        => date('Y-m-d H:i:s'),
                ];
                $postData[] = $attendance;
            }
        }
        return $postData;
    }

    //获取两个日期之间所有日期
    public function printDates($start, $end)
    {
        $dt_start = strtotime($start);
        $dt_end = strtotime($end);
        $date_array = [];
        while ($dt_start <= $dt_end) {

            $date_array[] = date('Y-m-d', $dt_start);
            $dt_start = strtotime('+1 day', $dt_start);
        }
        return $date_array;
    }
    /**
     * 根据日期统计当天的车队长上报数据
     * 注:返回数据以车牌号(驾驶员)作为键值的二维数组
     * @params $date 日期
     * @params $mark 标志 busNumber:车辆,driver:驾驶员
     */
    public function getReportData($date, $mark)
    {
        $date = date('Y-m-d', strtotime($date));
        //获取车队长上报数据
        $attendance_data = DB::table('akbus_attendance_data')
            ->where('date', $date)
            ->whereIn('type', ['半天修车', '全天修车', '半天请假', '全天请假', '半天停运', '全天停运', '半天检气瓶', '全天检气瓶'])
            ->get()
            ->toArray();
        if ($mark == 'driver') {
            $other_data = collect($attendance_data)->groupBy('name')->toArray();
        } else {
            $other_data = collect($attendance_data)->groupBy($mark)->toArray();
        }
        //整合处理车队长上报数据
        $result = [];
        if (count($other_data) > 0) {
            foreach ($other_data as $key => $value) {
                $line = implode(',', array_unique(array_column($value, 'line')));
                //用来存车队上报数据数组
                $post_data = [
                    '半天修车' => 0,
                    '全天修车' => 0,
                    '半天请假' => 0,
                    '全天请假' => 0,
                    '半天停运' => 0,
                    '全天停运' => 0,
                    '半天检气瓶' => 0,
                    '全天检气瓶' => 0,
                ];
                foreach ($value as  $va) {
                    $type = $va['type'];
                    $duration = $va['duration'] ?: 1; //默认值为1
                    $post_data[$type] = $duration;
                }
                $targetArray = [];
                //整合半天和全天
                $targetArray['fixTime'] = $post_data['半天修车'] + $post_data['全天修车'];
                $targetArray['leaveTime'] = $post_data['半天请假'] + $post_data['全天请假'];
                $targetArray['stopTime'] = $post_data['半天停运'] + $post_data['全天停运'];
                $targetArray['checkGas'] = $post_data['半天检气瓶'] + $post_data['全天检气瓶'];
                $targetArray['signDate'] = $date;
                $targetArray['line'] = $line ? $line : '';
                $result[$key] = $targetArray;
            }
        }
        return $result;
    }
    /**
     * 统计指定日期的车辆(司机)考勤
     * @params $date 指定日期
     * @params $mark 标志 busNumber:统计车辆考勤,driver:统计驾驶员考勤
     */
    public function getAttendanceData($date, $mark)
    {
        $date = date('Y-m-d', strtotime($date));
        //获取节假日期
        $festival = DB::table('akbus_holiday')->pluck('holiday_date')->toArray();
        //获取考勤记录
        switch ($mark) {
            case 'busNumber':
                $data = AttendanceCollect::query()
                    ->where('sign_date', $date)
                    ->where('is_del', 0)
                    ->orderBy('license_plate_num')
                    ->get();
                $data = collect($data)->groupBy('license_plate_num')->toArray();
                break;
            case 'driver':
                $data = AttendanceCollect::query()
                    ->where('sign_date', $date)
                    ->where('is_del', 0)
                    ->orderBy('driver')
                    ->get();
                $data = collect($data)->groupBy('driver')->toArray();
                break;
            default:
                # code...
                break;
        }

        $result = [];
        foreach ($data as $key => $item) {
            $line = implode(',', array_unique(array_column($item, 'line')));
            //计算时长 ,加班等
            $minDate = searchMin($item, 'start_sign_time');
            // $start_sign_time = UTC2Normal($minDate, 'H:i:s'); //最早打卡时间
            $maxDate = searchMax($item, 'end_sign_time');
            // $end_sign_time = UTC2Normal($maxDate, 'H:i:s'); //最晚打卡时间
            $workHour = number_format((strtotime($maxDate) - strtotime($minDate)) % 86400 / 3600, 1);
            $maxHours = UTC2Normal($maxDate, 'H');
            $normalHour = $maxHours <= 12 ? 4.5 : 5.5;
            if ($workHour >= $normalHour && $workHour < 10) {
                $normalTime = 0.5;
            } elseif ($workHour >= 10) {
                $normalTime = 1;
            } else {
                $normalTime = 0;
            }
            $overTime = in_array($date, $festival, true) ? 1 : 0; // 加班时间
            $nightOverTime = 0; //晚上加班时间(默认为0)
            $attendance = [
                $mark           => $key,
                'line'          => $line,
                'signDate'      => $date,
                'workHours'     => $workHour,
                'normalTime'    => $normalTime,
                'overTime'      => $overTime,
                'nightOverTime' => $nightOverTime,
            ];
            $result[$key] = $attendance;
        }
        return $result;
    }
    /**
     * 合并考勤汇总数据与车队长上报数据
     * @params $attendanceData  考勤汇总数据
     * @params $reportData  车队长上报数据
     * @params $mark  汇总标志 busNumber:汇总车辆,driver:汇总驾驶员
     */
    public function mergeData($attendanceData, $reportData, $mark)
    {
        //需要取两个数组的并集
        $attendanceDataKey = array_keys($attendanceData);
        $reportDataKey = array_keys($reportData);
        $keyArray = array_merge($attendanceDataKey, $reportDataKey); //合并
        $keyArray = array_unique($keyArray); //去重
        $result = [];
        foreach ($keyArray as $v) {
            $data = [
                $mark           => $v,
                'line'          => '',
                'signDate'      => '',
                'workHours'     => 0,
                'normalTime'    => 0,
                'overTime'      => 0,
                'nightOverTime' => 0,
                'fixTime'       => 0,
                'leaveTime'     => 0,
                'stopTime'      => 0,
                'checkGas'      => 0,
                'created_at'    => date('Y-m-d H:i:s'),
            ];
            if (in_array($v, $attendanceDataKey)) {
                $data['signDate'] = $data['signDate'] ?: $attendanceData[$v]['signDate'];
                $data['line'] = $data['line'] ?: $attendanceData[$v]['line'];
                $data['workHours'] = $data['workHours'] ?: $attendanceData[$v]['workHours']; //工作时长
                $data['normalTime'] = $data['normalTime'] ?: $attendanceData[$v]['normalTime']; //正常班
                $data['overTime'] = $data['overTime'] ?: $attendanceData[$v]['overTime']; //加班
                $data['nightOverTime'] = $data['nightOverTime'] ?: $attendanceData[$v]['nightOverTime']; //晚上加班
            }
            if (in_array($v, $reportDataKey)) {
                $data['signDate'] = $data['signDate'] ?: $reportData[$v]['signDate'];
                $data['line'] = $data['line'] ?: $reportData[$v]['line'];
                $data['fixTime'] = $data['fixTime'] ?: $reportData[$v]['fixTime']; //修车
                $data['leaveTime'] = $data['leaveTime'] ?: $reportData[$v]['leaveTime']; //请假
                $data['stopTime'] = $data['stopTime'] ?: $reportData[$v]['stopTime']; //停运
                $data['checkGas'] = $data['checkGas'] ?: $reportData[$v]['checkGas']; //检气瓶
            }
            $result[] = $data;
        }
        return $result;
    }
}
